import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class HelloClassLoader extends ClassLoader {

    public static void main(String[] args) throws Exception {
        System.out.println("=====");
        HelloClassLoader helloClassLoader = new HelloClassLoader(); // 类初始化
        Class<?> clazz = helloClassLoader.loadClass("Hello");
        // 打印一下原文件有哪些方法
        for (Method m : clazz.getDeclaredMethods()) {
            System.out.println(clazz.getSimpleName() + "." + m.getName());
        }
        // 创建对象
        Object instance = clazz.getDeclaredConstructor().newInstance();
        Method hello = clazz.getMethod("hello");
        hello.invoke(instance);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        System.out.println("findClass is called");
        final String suffix = ".xlass";
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(name+suffix);
        try {
            int length = inputStream.available();
            byte[] byteArray = new byte[length];
            inputStream.read(byteArray);
            // 将xlass文件里面的每个字节都255再次去减得到原码，这样就是原文件，才能找到对应方法
            byte[] decodeByteClass = decode(byteArray);
            // 将byte数组转为类的实例，通知底层定义这个类
            return defineClass(name, decodeByteClass, 0, decodeByteClass.length);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    private static byte[] decode(byte[] byteArray) {
        // 避免改掉原数组
        byte[] targetArray = new byte[byteArray.length];
        for (int i = 0; i < byteArray.length; ++i) {
            targetArray[i] = (byte) (255 - byteArray[i]);
        }
        return targetArray;
    }
}
